package com.forestar.mapControl.mapview;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.Display;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.TextureView;
import android.view.View;
import android.widget.Scroller;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.forestar.mapControl.mapview.multitouch.MoveGestureDetector;
import com.forestar.mapControl.mapview.multitouch.TestTextureViewRefreshListener;
import com.forestar.mapControl.mapview.multitouch.listener.MapViewGestureDetectorListener;
import com.forestar.mapControl.mapview.multitouch.listener.MoveGestureListener2;
import com.forestar.mapControl.mapview.multitouch.listener.ScaleGestureDetectorListener;
import com.forestar.mapControl.utils.LogD;
import com.forestar.mapControl.utils.mapConvert.MapConvert2;
import com.forestar.mapControl.utils.mapConvert.MapViewTransform;
import com.forestar.mapControl.utils.mapConvert.convert.ConvertHelper2;
import com.forestar.mapControl.utils.mapConvert.geometry.GeoPoint;
import com.forestar.mapControl.utils.mapConvert.geometry.coordinatesystem.CoordinateSystem;
import com.forestar.mapControl.utils.mapConvert.task.ConfigurablePriorityThreadFactory;
import com.forestar.mapControl.utils.tile.TileSchema;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import static com.forestar.mapControl.utils.mapConvert.task.DrawForTask.heightScreen;
import static com.forestar.mapControl.utils.mapConvert.task.DrawForTask.widthScreen;

/**
 * created by  xzk
 * 2020/7/27   14:31
 * 说明:  启动线程进行textureView刷新
 */
public class TestTextureView2 extends TextureView implements TextureView.SurfaceTextureListener, TestTextureViewRefreshListener {

    private MapConvert2 mapConvert;
//    private MapViewTransform mapViewTransform;
    private MapViewTransform mapViewTransform2;

    //一个缓存用的，应该就够了
    private CacheCanvas cacheCanvas;
    //一个缓存中介层，移动时用来反贴缓存层中心
//    private CacheCanvas cache2Canvas;
    private List<CacheCanvas> cacheLayerList;

    private GestureDetector gestureDetector;
    private MoveGestureDetector moveGestureDetector;
    private ScaleGestureDetector mScaleGestureDetector;
    private ThreadPoolExecutor refreshExecutor;
    private Paint testPaint = new Paint();

    private AtomicInteger referNum = new AtomicInteger(0);

    //视窗宽高
    private int width = 0;
    private int height = 0;
    private Scroller mScroller;

    public TestTextureView2(@NonNull Context context) {
        this(context, null, 0);
    }

    public TestTextureView2(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TestTextureView2(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        initView();
        initData();
    }

    /**
     * 初始化view参数，
     */
    private void initView() {
        setOpaque(true);//设置背景透明，记住这里是[是否不透明]
        setSurfaceTextureListener(this);//设置监听
        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setKeepScreenOn(true);
        setWillNotDraw(false);
        this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

    private int lastScrollForX = 0;
    private int lastScrollForY = 0;

    /**
     * 增加地图的滑动事件，
     */
    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller == null) { //fix for edit mode in the IDE
            return;
        }
        if (!mScroller.computeScrollOffset()) {
            return;
        }
        //使用这个判断才能达到惯性滑动的效果
        if (mScroller.isFinished()) {
            LogD.e("惯性停止");
            lastScrollForX = 0;
            lastScrollForY = 0;
        } else {
//            手劲大了，滑动的距离就长
            int offsetX = mScroller.getCurrX() - lastScrollForX;
            int offsetY = mScroller.getCurrY() - lastScrollForY;
//            LogD.e("滑动惯性：当前位置:("+ mScroller.getCurrX()+"，" +(mScroller.getCurrY())+")"
//                    +"最终位置:("+ mScroller.getFinalX()+"，" +(mScroller.getFinalY())+")"
//                    +"上次位置:(" +lastScrollForX+"<----->"+lastScrollForY
//                    +"差距距离:(" +offsetX+"<----->"+offsetY);
            move(offsetX, offsetY);
            lastScrollForX = mScroller.getCurrX();
            lastScrollForY = mScroller.getCurrY();
//            //必须要使用这个才能连续滑动
            invalidate();
        }
    }

    /**
     * 初始化展示参数，并准备好加载第一帧的参数，
     * <p>
     * 下一步，加载第一帧成功（准备好 MapConvert加载的所有参数，顺畅加载）
     * <p>
     * 读写权限，网络请求权限
     */
    private void initData() {
        //类似mapControl功能
        mScroller = new Scroller(getContext());
        refreshExecutor = new ThreadPoolExecutor(1, 1, 20L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(),
                new ConfigurablePriorityThreadFactory(Thread.NORM_PRIORITY, "刷新首页地图ui"),
                new ThreadPoolExecutor.DiscardOldestPolicy());

        mapConvert = new MapConvert2();

        // 这里的数据组合不能随意更改，需要一一对应上
//        mapViewTransform = new MapViewTransform(
//                CoordinateSystem.createMercator(),
//                widthScreen, heightScreen, 13555.687085453646, new PointF(1310030.3446F, 3586796.65173288f), 480);

        mapViewTransform2 = ConvertHelper2.buildMapViewTransform2() ;
        //设置默认中心点

//        mapViewTransform.setMapCenter(new GeoPoint(mapViewTransform2.getCoordinateSystem(), 1.3100303446E7, 3.58679665173288E6));
        mapViewTransform2.setMapCenter(116.391083,39.9073333);
        float screenPPI = mapConvert.getScreenPPI(getContext());
//        mapViewTransform.setDensityDPI(screenPPI);
        mapViewTransform2.setDensityDPI(screenPPI);

        Context aContext = getContext();
        //增加滚动状态监听
        gestureDetector = new GestureDetector(aContext, new MapViewGestureDetectorListener(mScroller, new MapViewGestureDetectorListener.OnScrollerListener() {
            @Override
            public void onStartScroll(float x, float y) {
                invalidate();
                lastScrollForX = (int) x;
                lastScrollForY = (int) y;
            }

            @Override
            public void onStopScroll(float x, float y) {
                lastScrollForX = 0;
                lastScrollForY = 0;
            }
        }));
        moveGestureDetector = new MoveGestureDetector(aContext, new MoveGestureListener2(this));
        mScaleGestureDetector = new ScaleGestureDetector(getContext(), new ScaleGestureDetectorListener());

        cacheCanvas = new CacheCanvas();
        cacheCanvas.reSize(mapViewTransform2, widthScreen, heightScreen);

        cacheLayerList = new ArrayList<>();
        for (int i = 0; i < 2; i++) {
            CacheCanvas cacheCanvas = new CacheCanvas();
            cacheCanvas.reSize(mapViewTransform2, widthScreen, heightScreen);
            cacheLayerList.add(cacheCanvas);
        }

        mapConvert.initData( cacheCanvas, null, cacheLayerList,getContext(), this);

//        mapConvert.initData(tileSchema,renderedCanvas,this);

        textPaint.setColor(Color.RED);
        textPaint.setTextSize(50);
        textPaint.setStrokeWidth(5);

        boxPaint.setColor(Color.GRAY);
        boxPaint.setTextSize(50);
        boxPaint.setStyle(Paint.Style.FILL);

        Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay();
        Point point = new Point();
        display.getSize(point);
        width = point.x;
        height = point.y;
        widthScreen = point.x;
        heightScreen = point.y;
//        //width = 1600.0,height = 2560.0
//        LogD.d( "width = " + width + ",height = " + height);
    }

    /**
     * 调用本方法，开始计算位移中心点，准备刷新事项
     * 刷新绘制
     */
    @Override
    public void reLoadScreenTile() {
        if (null != mapConvert) {
            try {
                mapConvert.loadingAllForScreen(mapViewTransform2,mapViewTransform2);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        LogD.d("尺寸发生变化:" + w + "<h>" + h);
        try {
            this.width = w;
            this.height = h;
            setViewSize(w, h);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //重置视窗宽高 横竖屏切换
    private void setViewSize(int w, int h) {
        if (w > 0 && h > 0) {
            mapViewTransform2.setViewSize(w, h);
            cacheCanvas.reSize(mapViewTransform2, w, h);
            reLoadScreenTile();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        try {
            if (event.getPointerCount() != 1) {
                mScaleGestureDetector.onTouchEvent(event);
            }
            moveGestureDetector.onTouchEvent(event);
            gestureDetector.onTouchEvent(event);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    @Override
    public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surfaceTexture, int i, int i1) {
        testPaint = new Paint();
        testPaint.setStyle(Paint.Style.FILL);
        testPaint.setColor(Color.RED);
        testPaint.setStrokeCap(Paint.Cap.ROUND);
        testPaint.setStrokeWidth(10);
        reLoadScreenTile();
    }

    @Override
    public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surfaceTexture, int i, int i1) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) {
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surfaceTexture) {

    }

    private AtomicBoolean refreshStatus = new AtomicBoolean(false);

    @Override
    public void refreshTextureView() {
        LogD.d("剩余次数："+referNum.get());
        if (referNum.get() < 2) {
            referNum.incrementAndGet();
            refreshExecutor.execute(renderingThread);
        }
    }

    @Override
    public void refreshFinishForComplete() {
        //刷新完毕，页面全部显示完毕
        refreshStatus.set(false);
    }

    //此处用来测试是否能够加载成功
    @Override
    public void refreshSingleTest(BitmapDrawable bitmapDrawable) {
//        bitmapDrawableTemp = bitmapDrawable;
//        synchronized (refreshExecutor) {
//            refreshExecutor.execute(renderingThread);
//        }
    }

    private BitmapDrawable bitmapDrawableTemp;

    private Paint textPaint = new Paint();
    private Paint boxPaint = new Paint();


    public Runnable renderingThread = new Runnable() {

        @Override
        public void run() {
            //锁定开始绘制
            Canvas screenCanvas = lockCanvas();
            if (null == screenCanvas) {
                return;
            }
            long start = System.currentTimeMillis();

            //把刷新任务让出来，
            referNum.decrementAndGet();
            LogD.d("剩余次数："+referNum.get());
//                //缓存清屏   移动过程中，进行重置缓存1

            screenCanvas.drawColor(Color.WHITE);
            screenCanvas.drawBitmap(cacheCanvas.getBitmap(), 0, 0, temppaint);
//            drawCacheCanvas(screenCanvas);
            long end = System.currentTimeMillis();

            String s = "本次绘制到屏幕：" + "<--渲染用时->" + (end - start);
            LogD.d("瓦片文件数量:" + s);
            drawText(screenCanvas, s);

            unlockCanvasAndPost(screenCanvas);
            if (referNum.get() > 0) {
                refreshExecutor.execute(renderingThread);
            }
        }

        //显示性能信息
        private void drawText(Canvas canvasCache, String content) {
            textPaint.setColor(Color.GRAY);
            canvasCache.drawRect(90, 50, textPaint.measureText(content) + 300, 130, textPaint);
            textPaint.setColor(Color.RED);
            canvasCache.drawText(content, 100, 100, textPaint);
        }
    };

    Paint temppaint = new Paint();

    //绘制画布
    private void drawCacheCanvas(Canvas screenCanvas, CacheCanvas cacheCanvas) {
        try {
            synchronized (cacheCanvas.lockObject) {
                MapViewTransform cacheTrans = cacheCanvas.getTransform();
                if (null == cacheTrans) {
                    return;
                }
                double resolutionScale = 0;
                int width = 0;
                int height = 0;
                PointF oriPointF;
                GeoPoint geoPoint = cacheTrans.screenPoint2MapPoint(0, 0);
                oriPointF = mapViewTransform2.mapPoint2ScreenPoint(geoPoint);
                //这里是 是对图片进行裁截，若是空null则显示整个图片
                Rect srcCacheRect = new Rect();
                srcCacheRect.left = 0;
                srcCacheRect.top = 0;
                srcCacheRect.right = (int) (cacheTrans.getScreenCenterX() * 2);
                srcCacheRect.bottom = (int) (cacheTrans.getScreenCenterY() * 2);
                resolutionScale = (cacheTrans.getResolutionInMapUnit() / cacheTrans.getResolutionInMapUnit());
                width = (int) (cacheTrans.getScreenCenterX() * 2 * resolutionScale);
                height = (int) (cacheTrans.getScreenCenterY() * 2 * resolutionScale);

                //是图片在Canvas画布中显示的区域
                Rect dstCanvasRect = new Rect();
                dstCanvasRect.left = (int) oriPointF.x;
                dstCanvasRect.top = (int) oriPointF.y;
                dstCanvasRect.right = (int) oriPointF.x + width;
                dstCanvasRect.bottom = (int) oriPointF.y + height;

                screenCanvas.drawBitmap(cacheCanvas.getBitmap(), srcCacheRect, dstCanvasRect, temppaint);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //移动的是相对距离
    public void move(float moveXPixels, float moveYPixels) {
        if (Math.abs(moveXPixels) < 2 && Math.abs(moveYPixels) < 2)
            return;
//        LogD.d("移动距离 moveXPixels:"+moveXPixels+"<---->"+moveYPixels);
        mapViewTransform2.move(moveXPixels, moveYPixels);
        reLoadScreenTile();
    }


}
